﻿using Microsoft.Media.FragmentedMediaSink;
using Microsoft.Media.ISO;
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.Media.MediaProperties;
using System.Threading.Tasks;
using Windows.Foundation;

namespace Microsoft.Media.CaptureClient
{
    public sealed class FragmentController : IFragmentController
    {
        Task activeTask;

        public event EventHandler<FragmentCreatedEventArgs> FragmentCreated;

        public IAsyncAction ActiveTask { get { return (activeTask ?? Task.FromResult<object>(null)).AsAsyncAction(); } }

        public FragmentController()
        {
            FragmentSize = TimeSpan.FromSeconds(2);
        }

        public IAsyncAction FragmentCompleted(IRandomAccessStream stream, uint streamIndex, uint fragmentIndex, ulong startTime, ulong endTime)
        {
            return _FragmentCompleted(stream, streamIndex, fragmentIndex, startTime, endTime).AsAsyncAction();
        }

        async Task _FragmentCompleted(IRandomAccessStream stream, uint streamIndex, uint fragmentIndex, ulong startTime, ulong endTime)
        {
            try
            {
                activeTask = stream.FlushAsync().AsTask().ContinueWith(t => // run the rest of this on the same background thread as the flush (instead of the one used by the caller).
                {
                    System.Diagnostics.Debug.WriteLine("Stream Size: {0}", stream.Size);
                    // save to file
                    //stream.Seek(0);
                    //var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(string.Format("{0}-{1}-{2}-{3}.mp4", fragmentIndex, streamIndex, startTime, endTime));
                    //var buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size);
                    //await stream.ReadAsync(buffer, (uint)stream.Size, InputStreamOptions.ReadAhead);
                    //await FileIO.WriteBufferAsync(file, buffer);

                    stream.Seek(0);
                    var args = new FragmentCreatedEventArgs(MP4BoxReader.ReadAllBoxes(stream).ToList(), streamIndex, fragmentIndex, startTime, endTime);
                    if (FragmentCreated != null) FragmentCreated(this, args);
                }, TaskContinuationOptions.OnlyOnRanToCompletion); //.Unwrap();
                await activeTask;
            }
            finally
            {
                activeTask = null;
                stream.Dispose();
            }
        }

        public IRandomAccessStream StartFragment()
        {
            return new InMemoryRandomAccessStream();
        }

        public TimeSpan FragmentSize { get; set; }

        public IMediaEncodingProperties EncodingProperties { get; set; }
    }

    public sealed class FragmentCreatedEventArgs
    {
        public FragmentCreatedEventArgs(IList<IBox> boxes, uint streamIndex, uint fragmentIndex, ulong startTime, ulong endTime)
        {
            Boxes = boxes;
            StreamIndex = streamIndex;
            FragmentIndex = fragmentIndex;
            StartTime = startTime;
            EndTime = endTime;
        }

        public IList<IBox> Boxes { get; private set; }

        public uint StreamIndex { get; private set; }

        public uint FragmentIndex { get; private set; }

        public ulong StartTime { get; private set; }

        public ulong EndTime { get; private set; }
    }
}
